package ecnu.ecgbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import ecnu.ecgbackend.config.redis.RedisService;
import ecnu.ecgbackend.dao.DeveloperMapper;
import ecnu.ecgbackend.dao.DoctorMapper;
import ecnu.ecgbackend.dao.PatientMapper;
import ecnu.ecgbackend.dao.UserMapper;
import ecnu.ecgbackend.entity.Developer;
import ecnu.ecgbackend.entity.Doctor;
import ecnu.ecgbackend.entity.Patient;
import ecnu.ecgbackend.entity.User;
import ecnu.ecgbackend.service.DiagnosisAccountService;
import ecnu.ecgbackend.utils.*;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Service
@Transactional
public class DiagnosisAccountServiceImpl implements DiagnosisAccountService {
    @Resource
    AuthenticationManager authenticationManager;
    @Resource
    JwtUtils jwtUtils;
    @Resource
    RedisService redisService;
    @Resource
    UserMapper userMapper;
    @Resource
    PatientMapper patientMapper;
    @Resource
    DoctorMapper doctorMapper;
    @Resource
    DeveloperMapper developerMapper;

    @Override
    public Map<String, Object> login(User user) {
        UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());
        Authentication authentication=authenticationManager.authenticate(authenticationToken);
        if(Objects.isNull(authentication)){
            return null;
        }
        User loginUser=(User) authentication.getPrincipal();
        String token=jwtUtils.generateToken(user);
        long expireTime= Jwts.parser()
                .setSigningKey(jwtUtils.getSecret())
                .parseClaimsJws(token.replace("jwt_",""))
                .getBody().getExpiration().getTime();
        Map<String,Object> map=new HashMap<>();
        map.put("user",userMapper.selectById(loginUser.getId()));
        map.put("token",token);
        map.put("expireTime",expireTime);
        if(loginUser.getRole().equals("patient")){
            map.put("info",patientMapper.selectById(loginUser.getId()));
        }else if(loginUser.getRole().equals("doctor")){
            map.put("info",doctorMapper.selectById(loginUser.getId()));
        }else if(loginUser.getRole().equals("developer")){
            map.put("info",developerMapper.selectById(loginUser.getId()));
        }
        String tokenKey="token_"+token;
        redisService.set(tokenKey,token,jwtUtils.getExpiration()/1000);
        return map;
    }

    @Override
    public Boolean logout(HttpServletRequest request, HttpServletResponse response) {
        String token=request.getParameter("token");
        if(ObjectUtils.isEmpty(token)){
            token=request.getHeader("token");
        }
        Authentication authentication= SecurityContextHolder.getContext().getAuthentication();
        if(authentication!=null){
            new SecurityContextLogoutHandler().logout(request,response,authentication);
            String key="token_"+token;
            redisService.del(key);
            return true;
        }
        return false;
    }

    @Override
    public Boolean logoff() {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",user.getId()).set("is_delete",1);
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public Result register(User user, String code) {
        User selectUser=userMapper.selectOne(new QueryWrapper<User>().eq("username",user.getUsername()));
        if(selectUser!=null){
            return Result.error().message("该用户名已被使用，请重新输入");
        }
        String _code=redisService.get(user.getPhone());
        if(_code==null){
            return Result.error().message("验证码已失效");
        }
        if(!code.equalsIgnoreCase(_code)){
            return Result.error().message("验证码错误");
        }
        BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
        user.setPassword(encoder.encode(user.getPassword()));
        userMapper.insert(user);
        User _user=userMapper.selectOne(new QueryWrapper<User>().eq("username",user.getUsername()));
        if(_user==null){
            return Result.error().message("注册失败");
        }
        //user表要填，其他表也要填
        String role=user.getRole();
        if(role.equalsIgnoreCase("patient")){
            Patient patient=new Patient(_user.getId(),null,3);
            if( patientMapper.insert(patient)>0){
                return Result.ok().message("注册成功！");
            }else {
                return Result.error().message("注册失败");
            }
        }else if(role.equalsIgnoreCase("developer")){
            Developer developer=new Developer(_user.getId(),null,null,null,null,null,3);
            if(developerMapper.insert(developer)>0){
                return Result.ok().message("注册成功！");
            }else {
                return Result.error().message("注册失败");
            }
        }else if(role.equalsIgnoreCase("doctor")){
            Doctor doctor=new Doctor(_user.getId(),null,null,null,null,null,null,null,null,null,false);
            if(doctorMapper.insert(doctor)>0){
                return Result.ok().message("注册成功！");
            }else {
                return Result.error().message("注册失败");
            }
        }else {
            return Result.ok().message("注册成功！");
        }
    }

    @Override
    public boolean updatePassword(String username,String password) {
        User user=userMapper.selectOne(new QueryWrapper<User>().eq("username",username));
        BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",user.getId())
                .set("password",encoder.encode(password));
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }
}
